
package threads;

import componentes.Cliente;
import componentes.Configuracao;
import componentes.Linux;
import componentes.Servidor;
import excessoes.IpNaoEcontradoException;
import excessoes.LloginNuloException;
import excessoes.clienteException.*;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import principal.Main;

/**
 *
 * @author Wagner Tavares
 */
public class ConsultaClientes extends Consulta{
    private Hashtable<String,Cliente> colecaoDeClientes;
    private Servidor servidor;
    private Thread consultaClientesThread;
    private String queryUnicoIP;
    
    public ConsultaClientes(Configuracao config,Servidor servidor,Hashtable<String,Cliente> clientes) throws LloginNuloException{
        super(config);
        this.servidor = servidor;
        String llogin = "" ;
        if(config.getLlogin().contains(",")){
            String [] logins = config.getLlogin().split(",");
            for(int i = 0 ; i < logins.length ; i++){
                llogin = llogin.concat("tbinsumocontrato.llogin = '"+logins[i]+"' ");
                if( i < (logins.length-1) )
                    llogin = llogin.concat("or ");
            }
        }else{
            llogin = "tbinsumocontrato.llogin = '"+config.getLlogin()+"' ";
        }
        this.query = "" +
                "SELECT \n" +
                    "tbinsumocontrato.detalhe, \n" +
                    "tbinsumocontrato.squid, \n" +
                    "tbinsumo.hora_inicial, \n" +
                    "tbinsumo.hora_final, \n" +
                    "tbinsumo.hora_inicial_fds, \n" +
                    "tbinsumo.hora_final_fds, \n" +
                    "tbinsumo.fds \n" +
                "FROM " +
                    "tbinsumocontrato, tbinsumo \n" +
                "WHERE ( "+llogin+" ) \n" +
                    "AND tbinsumocontrato.detalhe like 'M%' \n" +
                    "AND tbinsumocontrato.ativo='1' \n" +
                    "AND tbinsumocontrato.codigoInsumo = tbinsumo.codigoInsumo \n" +
                    "ORDER BY tbinsumocontrato.codigoInsumo, tbinsumocontrato.codigoContrato";
        colecaoDeClientes=clientes;
    }
    

    @Override
    public void run() {
        Hashtable<String,Cliente> clientesConsultados = new Hashtable<String,Cliente>();
        ResultSet resultado = consultaBanco(query);
        try{    
            while(resultado.next()){
                String detalhe = resultado.getString("tbinsumocontrato.detalhe");
                if(detalhe.contains("I")){
                    boolean fds=false,bloqueado=true, proxyTransparente = true;
                    String[] temp = resultado.getString("tbinsumocontrato.detalhe").substring(1).split("I");
                    if(resultado.getString("tbinsumo.fds")!=null && !resultado.getString("tbinsumo.fds").isEmpty() && resultado.getString("tbinsumo.fds").equals("S"))
                        fds = true;
                    if( colecaoDeClientes!=null && !colecaoDeClientes.isEmpty() && colecaoDeClientes.containsKey(temp[1])){
                        bloqueado = colecaoDeClientes.get(temp[1]).getBloqueado();}
                    if(!resultado.getString("tbinsumocontrato.squid").contains("S"))
                        proxyTransparente = false;
                    try {
                        clientesConsultados.put(
                                temp[1], 
                                new Cliente(
                                    bloqueado, 
                                    temp[1], 
                                    temp[0], 
                                    servidor,
                                    proxyTransparente,
                                    resultado.getString("tbinsumo.hora_inicial"), 
                                    resultado.getString("tbinsumo.hora_final"), 
                                    fds, resultado.getString("tbinsumo.hora_inicial_fds"), 
                                    resultado.getString("tbinsumo.hora_final_fds")));
                    } catch (HoraInvalidaException ex) {
                        Logger.getLogger(Main.class.getName()).logp(Level.SEVERE, this.getClass().getName(),"run()",ex.getMessage()+" => "+ex.getHoraInvalida());
                    }
                }else
                    Logger.getLogger(Main.class.getName()).logp(Level.WARNING, "ConsultaClientes", "run()","Divisor 'I' do campo tbinsumocontrato.detalhe não foi encontrado em "+detalhe);
            }
            if(colecaoDeClientes!=null && !colecaoDeClientes.isEmpty())
                colecaoDeClientes.clear();
            colecaoDeClientes.putAll(clientesConsultados);
            this.criaChainsIptablesMangle();
            this.aplicaBloqueadoOuLiberado();
        }catch(SQLException e){
           Logger.getLogger(Main.class.getName()).logp(Level.SEVERE, "ConsultaClientes", "run()"," Erro ao manipular resultados da consulta no banco de dados",e);
        }
        Main.serializar();
    }
    public void aplicaBloqueadoOuLiberado(){
        Collection c = colecaoDeClientes.values();
        for (Iterator it = c.iterator();it.hasNext();){
            Cliente cliente = (Cliente)it.next();
            SubThread aplicaEmUm = new SubThread(cliente);
            aplicaEmUm.start();
        }
    }
    public void criaChainsIptablesMangle() {
        StringBuffer ips = new StringBuffer();
        Collection c = colecaoDeClientes.values();
        for (Iterator it = c.iterator();it.hasNext();){
            Cliente cliente = (Cliente)it.next();
            ips.append(" "+cliente.getIp());
        }
        try {
            Linux.executa(Linux.pathProg+"/iptables_mangle.sh" + ips);
        } catch (ExecutarComandoLinuxException e) {
            Logger.getLogger(Main.class.getName()).logp(Level.SEVERE, "ConsultaClientes", "ExecutarComandoLinuxException()","Erro ao executar um comando linux: "+e.getComando(),e);
        }
    }
    private class SubThread extends Thread{
        Cliente cliente;
        public SubThread(Cliente cliente){
            this.cliente = cliente;
        }
        public void run(){
            try {

                cliente.aplicaBloqueadoOuLiberado();

            } catch (ExecutarComandoLinuxException ex) {
                Logger.getLogger(Main.class.getName()).logp(Level.SEVERE, ConsultaClientes.class.getName(),"aplicaBloqueadoOuLiberado()","Erro ao executar um comando linux: "+ex.getComando(), ex);
            } catch (IpSemForwardException ex) {
                Logger.getLogger(Main.class.getName()).logp(Level.WARNING, ConsultaClientes.class.getName(),"aplicaBloqueadoOuLiberado()",ex.getMessage()+": "+ex.getIp());
            } catch (MacSemForwardException ex) {
                Logger.getLogger(Main.class.getName()).logp(Level.WARNING, ConsultaClientes.class.getName(),"aplicaBloqueadoOuLiberado()",ex.getMessage()+": "+ex.getMac());
            } catch (RecebeuLetrasException ex) {
                Logger.getLogger(Main.class.getName()).logp(Level.SEVERE, ConsultaClientes.class.getName(),"aplicaBloqueadoOuLiberado()",ex.getMessage()+" | "+ex.getArrayProblema().toString());
            } catch (ForaDoHorarioNavegacaoException e){
                Logger.getLogger(Main.class.getName()).logp(Level.WARNING, ConsultaClientes.class.getName(),"aplicaBloqueadoOuLiberado()","Foi tentado liberar o ip "+e.getIp()+" que está fora do horário de navegação");
            }
        }
    }
    public void consultarUnicoIp(String ip) throws IpNaoEcontradoException{
        ResultSet resultado = consultaBanco(queryUnicoIP);
        try {
            if (resultado.next()) {
                String detalhe = resultado.getString("tbinsumocontrato.detalhe");
                if(detalhe.contains("I")){
                    boolean fds=false,bloqueado=true,proxyTransparente = true;
                    String[] temp = resultado.getString("tbinsumocontrato.detalhe").substring(1).split("I");
                    if(resultado.getString("tbinsumo.fds").equals("S"))
                        fds = true;
                    if(!resultado.getString("tbinsumocontrato.squid").contains("S"))
                        proxyTransparente = false;
                    try {
                        colecaoDeClientes.put(
                                temp[1], //ip
                                new Cliente(
                                    bloqueado,
                                    temp[1], // ip
                                    temp[0], // mac
                                    servidor,
                                    proxyTransparente,
                                    resultado.getString("tbinsumo.hora_inicial"),
                                    resultado.getString("tbinsumo.hora_final"),
                                    fds, //distincaoFds
                                    resultado.getString("tbinsumo.hora_inicial_fds"),
                                    resultado.getString("tbinsumo.hora_final_fds")
                                )
                        );
                    } catch (HoraInvalidaException ex) {
                        Logger.getLogger(Main.class.getName()).logp(Level.SEVERE, this.getClass().getName(),"consultarUnicoIp()",ex.getMessage()+" => "+ex.getHoraInvalida());
                    }
                }else
                    Logger.getLogger(Main.class.getName()).logp(Level.WARNING, "ConsultaClientes", "run()","Divisor 'I' do campo tbinsumocontrato.detalhe não foi encontrado em "+detalhe);
            }else {
                throw new IpNaoEcontradoException(ip);
            }
        } catch (SQLException ex) {
            Logger.getLogger(Main.class.getName()).logp(Level.WARNING, "ConsultaClientes", "run()","SQL Exception.");
        }
    }
    public void start(){
        consultaClientesThread = new Thread(this,"ConsultaClientesThread");
        consultaClientesThread.start();
    }
    public void start(String[] ip){
        consultaClientesThread = new Thread(this,"ConsultaClientesThread");
        consultaClientesThread.start();
    }
    public void stop(){
        consultaClientesThread = null;
    }
    public void setQueryUnicoIP(String ip){
        this.queryUnicoIP=query.substring(0,query.indexOf('%'))+ip+query.substring(query.indexOf('%'),query.length());
    }
}
